package com.league.blog.system.shiro;

import com.league.blog.system.shiro.custom.CustomRolesAuthorizationFilter;
import com.league.blog.system.shiro.custom.CustomSessionManager;
import com.league.blog.system.shiro.custom.KicoutSessionControlFilter;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * @author huanghq
 */
@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //SecurityManager 安全管理器
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        //登录，为后台接口名，非前台页面名, 未登录跳转
        shiroFilterFactoryBean.setLoginUrl("/login");
        //登录成功后跳转的地址，为后台接口名，非前台页面名
        shiroFilterFactoryBean.setSuccessUrl("/");
        //无权限跳转
        shiroFilterFactoryBean.setUnauthorizedUrl("/error/unauthorized");

        //设置自定义filter
        Map<String, Filter> cusFilterMap = new LinkedHashMap<>();
        cusFilterMap.put("roleOn", customRolesAuthorizationFilter());
        cusFilterMap.put("kicout", kicoutSessionControlFilter());
        shiroFilterFactoryBean.setFilters(cusFilterMap);


        // 配置访问权限 必须是LinkedHashMap，因为它必须保证有序
        // 过滤链定义，从上向下顺序执行
        LinkedHashMap<String, String> filterMap = new LinkedHashMap<String, String>();

        filterMap.put("/", "anon");
        filterMap.put("/p/**", "anon");
        filterMap.put("/article/**", "anon");

        //解锁用户，暂时设为所有人可以访问
        filterMap.put("/unlockAccount", "anon");
        //对静态资源放行
        filterMap.put("/css/**", "anon");
        filterMap.put("/fonts/**", "anon");
        filterMap.put("/js/**", "anon");
        filterMap.put("/plugins/**", "anon");
        filterMap.put("/images/**", "anon");
        filterMap.put("/img/**", "anon");

        //logout是shiro提供的过滤器
        filterMap.put("/logout", "logout");

        filterMap.put("/editor/**", "user");
        filterMap.put("/user/**", "user");
        //文章实时保存
        filterMap.put("/articleRealSave/**", "user");

        filterMap.put("/root/**", "roles[root]");

        //其他资源都需要认证才能访问
        filterMap.put("/**", "kicout,user");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 配置核心安全管理器
     * @return
     */
    @Bean(name = "securityManager")
    public SecurityManager securityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(defaultRealm());

        securityManager.setCacheManager(redisCacheManager());

        securityManager.setSessionManager(sessionManager());
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }

    @Bean
    public DefaultRealm defaultRealm(){
        DefaultRealm realm = new DefaultRealm();

        return realm;
    }


    /**
     * 自定义session管理
     * @return
     */
    @Bean
    public SessionManager sessionManager(){
        CustomSessionManager sessionManager = new CustomSessionManager();
        //session过期时间 1800000为半小时
        sessionManager.setGlobalSessionTimeout(1800000);

        //配置session持久化
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
    /**
     * redisManager
     */
    @Bean
    public RedisManager redisManager(){
        RedisManager redisManager = new RedisManager();

//        redisManager.setHost(redisHost);
//        redisManager.setPort(redisPort);
        //设置过期时间
        redisManager.setExpire(2000);
        return redisManager;
    }

    /**
     * 配置具体catch实现类
     * @return
     */
    @Bean
    public RedisCacheManager redisCacheManager(){
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());


        return redisCacheManager;
    }

    /**
     * session持久化
     * @return
     */
    @Bean
    public RedisSessionDAO redisSessionDAO(){
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }

    /**
     * 管理shiro一些bean的生命周期 初始化和销毁
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){
        return new LifecycleBeanPostProcessor();
    }


    /**
     * 并发登录限制
     * @return
     */
    @Bean
    public KicoutSessionControlFilter kicoutSessionControlFilter(){
        KicoutSessionControlFilter kicoutSessionControlFilter = new KicoutSessionControlFilter();

        kicoutSessionControlFilter.setMaxNum(1);
        kicoutSessionControlFilter.setSessionManager(sessionManager());
//        kicoutSessionControlFilter.setRedisUtils(redisUtils());

        return kicoutSessionControlFilter;
    }

    /**
     * 自定义拦截器 单权限校验
     * @return
     */
    @Bean
    public CustomRolesAuthorizationFilter customRolesAuthorizationFilter(){
        CustomRolesAuthorizationFilter customRolesAuthorizationFilter = new CustomRolesAuthorizationFilter();
        return customRolesAuthorizationFilter;
    }

    @Bean
    public SimpleCookie rememberMeCookie() {
        //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //如果httyOnly设置为true，则客户端不会暴露给客户端脚本代码，使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击；
        simpleCookie.setHttpOnly(true);
        //记住我cookie生效时间,单位是秒
        //15天
        simpleCookie.setMaxAge(1000 * 60 * 60 * 24 * 15);
        return simpleCookie;
    }

    @Bean
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        //cookie加密的密钥
        byte[] cipherKey = Base64.decode("pqHe2Cc+4ac3v4WaeazXuw==");
        cookieRememberMeManager.setCipherKey(cipherKey);
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }

}
